﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Log2File;

namespace MessagePush
{
    public partial class ClientSeverForm : Form
    {
        //private System.ComponentModel.Container components = null;  
        //Clients数组保存当前在线用户的Client对象  
        internal static Hashtable clients = new Hashtable();
        //该服务器默认的监听端口号  
        private TcpListener listener;
        // 服务器可以支持的客户端的最大连接数  
        static int MAX_NUM = 100;
        //服务器开始服务的标志  
        internal static bool SocketServiceFlag = false;  


        public ClientSeverForm()
        {
            
            InitializeComponent();
        }




        #region 获取地址
        ////获取本地局域网IP地址  
        private string getIPAddress()
        {
            IPAddress[] AddressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList;// Dns.GetHostByName(Dns.GetHostName()).AddressList;  
            for (int i = 0; i < AddressList.Length; i++)
            {
                //从IP地址列表中筛选出IPv4类型的IP地址
                //AddressFamily.InterNetwork表示此IP为IPv4,
                //AddressFamily.InterNetworkV6表示此地址为IPv6类型
                if (AddressList[i].AddressFamily == AddressFamily.InterNetwork)
                {
                    if (int.Parse(AddressList[i].ToString().Split('.')[2])<10)
                        return AddressList[i].ToString();
                }
            }
            return "";
            //if (AddressList.Length < 1)
            //{
            //    return "";
            //}
            //return AddressList[0].ToString();
        }
        #endregion  


        #region 获取服务器端口号，并判断端口号是否合法
        //获取服务器的端口号，判读端口号是否合法  
        private int getValidPort(string port)
        {
            int lport;
            //测试端口号是否有效  
            try
            {
                //是否为空  
                if (port == "")
                {
                    Console.WriteLine("端口号为空，不启动服务器");
                }
                //将端口号转为int类型  
                lport = System.Convert.ToInt32(port);
            }
            catch (Exception e)
            {
                Console.WriteLine("无效的端口号:" + e.ToString());
                this.rtbSocketMsg.AppendText("无效的端口号:" + e.ToString());
                return -1;
            }
            return lport;
        }
        #endregion  



        #region 点击"启动Socket"按钮触发的事件,开始监听
        //启动"Socket"，开始监听  
        private void btnSocketStart_Click(object sender, EventArgs e)
        {
            //参数为端口号的值  
            int port = getValidPort(tbSocketPort.Text);
            if (port < 0)
            {
                return;
            }
            string ip = this.getIPAddress();
            try
            {
                IPAddress ipAdd = IPAddress.Parse(ip);
                //创建服务器套接字  
                listener = new TcpListener(ipAdd, port);
                //开始监听服务器端口  
                listener.Start();
                this.rtbSocketMsg.AppendText("Socketr服务器已经启动，正在监听" + ip + "  端口号：" + this.tbSocketPort.Text);
                //MessageBox.Show(Log.path);
                try
                {
                    Log.log("Socketr服务器已经启动，正在监听" + ip + "  端口号：" + this.tbSocketPort.Text);
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
               

                //启动一个新的线程，执行方法this.StratSockListen  
                //以便在一个独立的进程中执行确认与客户端Socket连接的操作  
                ClientSeverForm.SocketServiceFlag = true;
                Thread thread = new Thread(new ThreadStart(this.StartSocketListen));
                thread.Start();
                this.btnSocketStart.Enabled = false;
                this.btnStop.Enabled = true;
            }
            catch (Exception ex)
            {
                this.rtbSocketMsg.AppendText(ex.Message.ToString() + Environment.NewLine);
            }
        }
        #endregion

        #region 当有用户添加进来，将其添加到用户列表，更新在线人数
        public void addUser(string username)
        {
            //将刚链接的用户名加入到当前在线用户列表  
            SetControlText(rtbSocketMsg, username + "已经加入\n");
            //this.rtbSocketMsg.AppendText(username + "已经加入\n");  
            //跟新在线人数加1  
            SetControlList(lbSocketClients, username);
            // this.lbSocketClients.Items.Add(username);     
            //显示在线人数  
            SetControlText(tbSocketClientsNum, clients.Count.ToString());
            //this.tbSocketClientsNum.Text = System.Convert.ToString(clients.Count);  
        }
        #endregion



        void timer_Elapsed(object sender)
        {
            var nowTime = DateTime.Now;
            System.Collections.IEnumerator myEnumerator = ClientSeverForm.clients.Values.GetEnumerator();//ChatClientForm.clients.Values.GetEnumerator();  
            Log.log("timer tick");
            while (myEnumerator.MoveNext())
            {
                Client client = (Client)myEnumerator.Current;
                var lastLastHeartbeatTime = client.LastHeartbeatTime();
                var diffSeconds = (nowTime - lastLastHeartbeatTime).TotalSeconds;
                Log.log("name=" + client.Name + ",LastHeartbeatTime=" + lastLastHeartbeatTime.ToLongTimeString());
                Log.log("距上次心跳相隔时间(秒)=" + diffSeconds);
                if (diffSeconds > 10)
                {
                    Log.log("退出");
                    client.Server2Client_quit();

                    Hashtable syncClients = Hashtable.Synchronized(ClientSeverForm.clients);
                    syncClients.Remove(client.Name);
                    SetExit(lbSocketClients, client.Name);
                    SetControlText2(tbSocketClientsNum, clients.Count.ToString());
                    break;
                }
            }
        }


        #region 启动新的进程来处理和该客户端的信息交互
        //在新的线程中的操作，它主要用于当接收到一个客户端请求时，确认与客户端的链接  
        //并且立刻启动一个新的进程来处理和该客户端得信息交互  
        private void StartSocketListen()
        {
            System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(timer_Elapsed), null, 0, 10000);
            while (ClientSeverForm.SocketServiceFlag)
            {
                try
                {
                    //当接收到一个客户端请求时，确认与客户端的链接  
                    if (listener.Pending())
                    {
                        //接收挂起的连接请求  
                        Socket socket = listener.AcceptSocket();
                        if (clients.Count >= MAX_NUM)
                        {
                            this.rtbSocketMsg.AppendText("已经达到了最大连接数：" + MAX_NUM + ",拒绝接收新的链接");
                            socket.Close();
                        }
                        else
                        {
                            //启动一个新的线程  
                            //执行方法this.ServiceClient,处理用户相应的请求  
                            Client client = new Client(this, socket);
                            Thread clientService = new Thread(new ThreadStart(client.ServiceClient));
                            clientService.Start();
                        }
                    }
                    //是线程休息，提高系统性能  
                    Thread.Sleep(200);
                }
                catch (Exception ex)
                {
                    this.rtbSocketMsg.AppendText(ex.Message.ToString() + Environment.NewLine);
                }
            }
        }
        #endregion

        #region 输入端口号的文本框发生改变时
        private void tbSocketPort_TextChanged(object sender, EventArgs e)
        {
            //当端口号为空时，启动按钮亏掉不可用  
            this.btnSocketStart.Enabled = (this.tbSocketPort.Text != "");
        }
        #endregion

        #region 点击“停止”按钮，触发的事件
        private void btnStop_Click(object sender, EventArgs e)
        {
            listener.Stop();
            ClientSeverForm.SocketServiceFlag = false;
            this.btnSocketStart.Enabled = true;
            this.btnStop.Enabled = false;
            this.rtbSocketMsg.AppendText(Environment.NewLine + "停止监听\n");
        }
        #endregion

        #region 当有用户离开，将其在列表中删除，在线人数跟新减少一个
        public void removeUser(string username)
        {
            SetControlText(rtbSocketMsg, username);
            // this.rtbSocketMsg.AppendText(username + "已经离开");  
            //将其用户名移除用户表  
            SetExit(lbSocketClients, username);
            //this.lbSocketClients.Items.Remove(username);  
            //跟新在线人数  
            //this.tbSocketClientsNum.Text =System.Convert.ToString(clients.Count);  
            SetControlText(tbSocketClientsNum, clients.Count.ToString());
        }
        #endregion

        #region 用于在获取当前全部在线用户的列表，备用户名中间用“|”分割，该函数在LIST命令时调用
        public string GetUserList()
        {
            string Rtn = "";
            for (int i = 0; i < lbSocketClients.Items.Count; i++)
            {
                Rtn = Rtn + lbSocketClients.Items[i].ToString() + "|";
            }
            return Rtn;
        }
        #endregion

        #region 用于更新界面，添加系统或者聊天信息，参数是要显示的字符串
        public void updateUI(string msg)
        {
            SetControlText(rtbSocketMsg, msg);
            //this.rtbSocketMsg.AppendText(msg + Environment.NewLine);  
        }
        #endregion

        #region 当关闭窗口，会执行窗口的closing事件
        private void btn_Close_Click(object sender, System.ComponentModel.CancelEventArgs e)
        {
            ClientSeverForm.SocketServiceFlag = false;
        }
        #endregion

        #region 定义一个委托
        private delegate void SetControlTextDelegate(Control control, string txt);
        //判断当前控件是否在此线程中，当是此线程时，调用该线程  
        //如果不是同一线程，让其回调  
        private void SetControlText(Control control, string txt)
        {
            if (control.InvokeRequired)
            {
                var d = new SetControlTextDelegate(SetControlText);
                BeginInvoke(d, new object[] { control, txt });
            }
            else
            {
                control.Text = control.Text + Environment.NewLine + txt;
            }
        }

        private void SetControlText2(Control control, string txt)
        {
            if (control.InvokeRequired)
            {
                var d = new SetControlTextDelegate(SetControlText2);
                BeginInvoke(d, new object[] { control, txt });
            }
            else
            {
                control.Text = txt;
            }
        }

        private delegate void SetControlListDelegate(ListBox listbox, string txt);
        //判断当前控件是否在此线程中，当是此线程时，调用该线程  
        //如果不是同一线程，让其回调  
        private void SetControlList(ListBox listbox, string item)
        {
            if (listbox.InvokeRequired)
            {
                var d = new SetControlListDelegate(SetControlList);
                BeginInvoke(d, new object[] { listbox, item });
            }
            else
            {
                listbox.Items.Add(item);
            }
        }

        private delegate void SetExitDelegate(ListBox listbox, string item);
        //判断当前控件是否在此线程中，当是此线程时，调用该线程  
        //如果不是同一线程，让其回调  
        private void SetExit(ListBox listbox, string item)
        {
            if (listbox.InvokeRequired)
            {
                var d = new SetExitDelegate(SetExit);
                BeginInvoke(d, new object[] { listbox, item });
            }
            else
            {
                listbox.Items.Remove(item);
            }
        }
        #endregion  

        private void ClientSeverForm_Load(object sender, EventArgs e)
        {

        }

        private void buttonSend_Click(object sender, EventArgs e)
        {
            string userName = lbSocketClients.SelectedItem.ToString();

            Client client = new Client(this,userName, this.textBoxMessage.Text);
            Thread clientService = new Thread(new ThreadStart(client.Server2Client));
            clientService.Start();
        }

        private void ClientSeverForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            Application.Exit();
            System.Environment.Exit(0);
        }

    }
}
